﻿using System;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Windows;
using System.Windows.Threading;
using XamlLocalizer.Parsing;
using XamlLocalizer.Tools;
using XamlLocalizer.Services;

namespace XamlLocalizer.ViewModels
{
    public class FindUnlocalizedFilesViewModel : INotifyPropertyChanged
    {
        private readonly IVisualStudioAdapter visualStudioAdapter;
        private string filesList;
        private bool lookInCurrentProject;
        private bool lookInSolution = true;
        private bool progressIsIndeterminate;
        private string progressText = "Search not started";
        private bool isCanceled;

        public FindUnlocalizedFilesViewModel(IVisualStudioAdapter visualStudioAdapter)
        {
            this.visualStudioAdapter = visualStudioAdapter;
            FindCommand = new DelegateCommand(DoFind, _ => !ProgressIsIndeterminate);
            CancelCommand = new DelegateCommand(DoCancel);
        }

        public bool LookInSolution
        {
            get { return lookInSolution; }
            set
            {
                if (lookInSolution != value)
                {
                    lookInSolution = value;
                    RaisePropertChanged("LookInSolution");
                    LookInCurrentProject = !lookInSolution;
                }
            }
        }

        public bool LookInCurrentProject
        {
            get { return lookInCurrentProject; }
            set
            {
                if (lookInCurrentProject != value)
                {
                    lookInCurrentProject = value;
                    RaisePropertChanged("LookInCurrentProject");
                    LookInSolution = !lookInCurrentProject;
                }
            }
        }

        public string ProgressText
        {
            get { return progressText; }
            private set
            {
                if (progressText != value)
                {
                    progressText = value;
                    RaisePropertChanged("ProgressText");
                }
            }
        }

        public bool ProgressIsIndeterminate
        {
            get { return progressIsIndeterminate; }
            private set
            {
                if (progressIsIndeterminate != value)
                {
                    progressIsIndeterminate = value;
                    RaisePropertChanged("ProgressIsIndeterminate");
                }
            }
        }

        public string FilesList
        {
            get { return filesList; }
            private set
            {
                if (filesList != value)
                {
                    filesList = value;
                    RaisePropertChanged("FilesList");
                }
            }
        }

        public DelegateCommand FindCommand { get; private set; }

        public DelegateCommand CancelCommand { get; private set; }

        public Window Window { get; set; }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        private void RaisePropertChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        private void DoFind(object obj)
        {
            if (ProgressIsIndeterminate) return;

            ProgressIsIndeterminate = true;
            FindCommand.RaiseCanExecuteChanged();

            ThreadPool.QueueUserWorkItem(FindProcessor);
        }

        private void FindProcessor(object state)
        {
            isCanceled = false;

            var sb = new StringBuilder();
            int filesCount = 0;
            try
            {
                foreach (string file in visualStudioAdapter.GetAllXamlFiles(LookInCurrentProject))
                {
                    if (isCanceled) break;
                    try
                    {
                        ProgressText = String.Format("Checking file {0}", file);

                        if (ContainsUnlocalizedStrings(file))
                        {
                            sb.AppendLine(file);
                            filesCount++;
                        }
                    }
                    catch (Exception e)
                    {
                        sb.AppendLine("Error: " + e.Message);
                    }
                }
            }
            catch (Exception e)
            {
                sb.AppendLine("Error: " + e.Message);
            }
            FilesList = sb.ToString();

            if (filesCount == 0)
            {
                ProgressText = "All XAML files seems to be localized";
            }
            else
            {
                ProgressText = String.Format("Found {0} not localized XAML files", filesCount);
            }

            ProgressIsIndeterminate = false;
            InvokeInUIThread(() => FindCommand.RaiseCanExecuteChanged());
        }

        private static bool ContainsUnlocalizedStrings(string file)
        {
            var xamlExtractor = new XamlExtractor(file, true);
            return (xamlExtractor.ParseResult.NewItems.Count > 0);
        }

        private void DoCancel(object obj)
        {
            if (ProgressIsIndeterminate)
            {
                isCanceled = true;
            }
            else
            {
                Window.Close();
            }
        }

        private void InvokeInUIThread(Action action)
        {
            Window.Dispatcher.Invoke(DispatcherPriority.Normal, action);
        }
    }
}